|
Chapter 11 |
Introduction
Debugger Control
STOP Commands and Breakpoints
Memory Windows
Variable Windows
Debugger Settings
Debugger Error Messages
Practical Examples
Introduction
If you have written computer programs already, you are probably familiar with the problem that a program
can behave differently than expected. It is usually rather difficult to find a simple typo or even a systematic
error without some sort of aid because the program's processing is for the most part not visible.
The source code debugger now gives you the means to search for specific errors. Just halt your program when suitable
and then work forward in single steps. You can then monitor how variables or memory content is changing and thus
determine exactly at which location your program exhibits unexpected behavior. A small triangle in the source code
always shows the current program pointer position when debugging.
Moreover, the source code debugger is also well suited for didactic purposes. Instructors can use the individual
steps of the debugger to teach their students about the function of an algorithm.
For this purpose, the animation mode can be used as well, which executes a program in slow motion, showing every
individual step in detail.
Debugger Control
To be able to debug a program, you first have to move the window with the source code to the front and then
select the menu option 'Debug' from the 'Program' menu. The program is then compiled in a special format, which
enables the debugger to monitor and control the program execution at any time. The following potential error sources
are monitored as well:
- Integer overflows with byte, integer, and long integer numbers. For example: A%=32768 or A%L=10^12 would trigger such an error.
- Floating point underflows and floating point overflows. These errors occur when the result of a calculation cannot be depicted in the applied number format (e.g., A#=10^100*10^250 or A!=10^-45).
- Divisions by zero.
- Illegal operations such as A#=LN(-1).
- BASIC stack overflow. This can happen, e.g., when sorting large fields or during recursive programming with large interleaf depths.
- In case of field variables, it is checked whether the specified indices are located in the range for which the field has been dimensioned, e.g., DIM A#(2,3):A#(3,2)=1 would trigger such an error.
If one of these errors occurs, an alert box is shown first describing the error. After leaving the alert box the Debugger Control appears. You can now open memory and variable windows and find out what caused the error. If it is not a fatal error, the program may continue; otherwise, it is always terminated when you try to continue.
Of course, there is a variety of other traps waiting for the programmer, which cannot be recognized by the debugger due to their nature (e.g., LPOKE 12,-1, or if you are using the Extension Library but have forgotten to add Extension_Init to the beginning of the program). Do not try this because it is sure to crash your computer!
For the debugger to be able to process all of these tasks, a table is created establishing a link between the source code and the object code generated by the compiler. The program can thus not be edited during the debugging phase. Therefore, do not think that your computer has crashed just because you cannot change your program any longer.
The program is started automatically after compilation is complete. The programs generated with 'Debug' run
somewhat slower than when using the menu option 'Compile & Start' due to the many management tasks that have
to be processed. However, this should not come into play when searching for errors.
Note: If you are using the Lite or the Demo version it may be that a program
can be compiled normally but cannot be debugged. The reason for this is the additional object code generated in
the debugging mode, which results in a program that is too long for the Lite or Demo version.
After the debugger has started your program, a small window opens containing the Debugger Control. The window has
7 buttons, which may be used to control the progress of your program. The control options are as follows:
[Stop]
Your program comes to an immediate stop if you click on this button. The window with the source code also
automatically scrolls to the spot where the program stopped and marks this location with a small triangle. This
function can also be called by pressing [Ctrl]+[C].
Attention: If your program does not make any regular calls of COMPILER "EVENT" or EasyMesag (in the case of programming with EasyGem) the program can be stopped only by pressing [Ctrl]+[C].
[Continue]
This button can be selected only if a program has been stopped. When you click on this button, the program
execution is continued with the command to which the small triangle is pointing.
[Step into]
This button can be selected only if a program has been stopped. When you click on this button, only the
one command to which the small triangle is pointing is executed. If it is a procedure or function call, the program
pointer jumps into the procedure or function. The same applies to GOSUB commands.
Please note that functions can also occur in formulas. In that case, all functions occurring in the formula are
entered into.
If the procedure or function has been supplied by a library, the debugger does not enter the subprogram. This would actually serve no purpose since the program code in the library is not listed and you cannot monitor the progress of the program as it is.
Note: A few of the library commands use callback functions, which you have
to define yourself and which are thus not located in the library (e.g., Uwin_Open
from the EasyGem Library). If you now call library commands using [Step into], the program pointer does not jump
into the library but could land in your callback routine if this is just now being called from within the library.
Unless you intend this action, it is better to use the button [Single Step] to avoid any such confusion.
[Step out]
This button can be selected only if a program has been stopped. It serves to trigger a procedure or function
without having to execute all commands within the procedure or function in individual steps. To be exact, the program
execution is continued until the debugger meets up with a RETURN, END_PROC, END_FN,
or EXIT, which is located at the same hierarchy level as the program pointer was
when this button was clicked.
After the button has been selected, the program pointer is then located directly behind the command used to call
the procedure or function. The same applies if subprograms are called via GOSUB commands.
Note: If you are using this button while the program pointer is not located in a subprogram, it will have the same effect as [Continue], because no RETURN commands are located in the uppermost hierarchy level.
[Single Step]
This button can be selected only if a program has been stopped. This function is similar to the function
of the [Step into] button with the one difference that subprogram calls are always interpreted like BASIC commands
and therefore is never be stopped in subprograms.
[Animation]
This button can be selected only if a program has been stopped. This will continue the program in slow motion.
The standard settings ensures that the debugger executes max. one command per second. This interval can also be
changed using the dialog box 'Debugger Settings'.
[Terminate]
This button can always be selected. It may be used to terminate the program controlled by the debugger at any time.
This closes the window for the Debugger Control automatically.
Attention: A few Omikron Basic commands wait for user input before continuing
the program. Since the debugger can halt a program only in-between two commands but not actually in the middle
of a command, the debugging command in these cases does not become effective until the command has been concluded.
These are the Omikron Basic commands INPUT, LINE INPUT, FORM_ALERT, and FILESELECT
or FSEL INPUT, as well as the EasyGem commands Easy_Alert,Easy_Fsel,
Easy_Fnav, and Pick_Color.
For example, if your program is in an INPUT instruction and you click on [Terminate],
the program is not terminated until the user has exited the input instruction with [Return].
If you stop your program using the Debugger Control, the spot where the program stops is more or less selected at random. But there are two other possibilities, which will halt the program in a specifically selected location.
STOP Command
Even before starting your program with 'Debug' just insert a STOP command
at the location where the program is to stop. Those who used to work with BASIC interpreters are probably familiar
with this method. The STOP command halts a program without deleting variable and memory contents.You can then continue
the program in a targeted manner using the Debugger Control.
Attention: The STOP command functions only
if the program has been started with 'Debug'. A normally compiled program using the STOP
command will lead to an error message with subsequent termination of the program.
Breakpoints
Breakpoints are additional stopping points, which you can include in your program. Contrary to STOP commands, breakpoints cannot be set until the program has been started with 'Debug'.
Just pull the source code window to the front, press the [Ctrl] key, and click on the spot in the source code where
the breakpoint is to be set. A small ellipsis appears in the color of the commentary lines. As soon as the program
pointer is now running across this spot, the program is halted and you can use the Debugger Control for a detailed
analysis. If you click on a breakpoint again, it is removed.
You can set as many breakpoints as desired. Contrary to STOP commands, breakpoints
are only effective during a debugging phase. After the program is finished they are automatically deleted. They
also cannot be copied to the clipboard or saved. If you would like to insert permanent breakpoints into your program
you have to use the STOP command.
Note: You cannot set breakpoints in all locations of a program because some lines, such as a commentary line, are skipped by the compiler and some BASIC commands serve only to structurize but do not generate an object code. In these cases, the breakpoint appears in the next possible location before the position on which you clicked.
Attention: If you are using the EasyGem Library or have programmed your
own event handling routine, your program cannot restore the contents of windows once it has been halted by the
debugger.
This does not apply to Omikron Basic output windows. These are managed by a small assembler program, which continues
to run even when the BASIC program has been halted by the debugger.
Memory Windows
Memory windows can be opened with the menu options carrying the same name from the 'Program' menu. Memory windows
are used to view the content of RAM memory.
There is an input line in the upper left corner of the window, which may be used to specify at which logical address
the memory content view is to start. The address can be prefixed and indicated in all number systems supported
by Omikron Basic (e.g., $A6553 or 123456). Pushing
[Return] shows the memory content starting with the specified address.
If the specified memory range does not exist, an error message appears and nothing is shown.
The type of display can be set via the Debugger Settings.
Variable Windows
You can enter the names of variables into the variable windows. Their content is then shown in the same
window. For string variables the length of the strings are indicated as well.
Only constants or individual variables may be used for the indices of field variables (e.g., A#(X,Y)
or A#(1,3)). As long as a program has not been started with 'Debug' the content
of variables is, of course, 0 and an empty string for strings.
The number system to display the variable content can be set with a prefix. For example, the input of $Tex$
would output the content of the string Tex$ as a byte sequence in hex numbers and
not as a character string. Similarly, the input of %A would result in the variable
content A as a binary number. According to the default setting, the output of numerical
variables is always in the form of decimal numbers and strings are always output as character strings.Strings can
also be output as a decimal byte sequence by prefixing with the number symbol "#."This is of special interest if one is interested in the ASCII values of a string.
Block functions also work in variable windows. Instead of typing in the desired variables, you can transfer them
from the program window using 'Copy' and 'Paste'.
Variable windows can also be saved, reloaded, or printed. The format for saving is ASCII. If they are reloaded,
the variables are assigned to the currently topmost program window.
If a variable does not exist or a field element is not located within the dimensioned range, the line is marked
in red to indicate an error line (red is the default setting).
A variable window always refers to a specific program window. If the window is closed, all linked variable windows
are automatically closed as well, because the variables contained in the program window are no longer defined.
Modifications to the variable windows can be set in the Debugger Settings dialog.
Debugger Settings
It is, of course, possible to configure all important functions of the debugger individually. For this purpose,
the dialog 'Debugger Settings' called from the dialog box 'Preferences' is used. The dialog box can remain open
while you work with the debugger so that you can change the settings, e.g., the animation speed, during a running
animation process.
The dialog is divided into the areas Memory Windows and General.
Memory Windows:
A Memory Window can be used to view the content of the RAM memory.
The display can vary.
Bytes per group:
This popup menu is used to specify how many bytes are displayed next to each other until a blank space is inserted.
Bytes per line:
This value indicates how many bytes are displayed in one line.
Display addresses as:
Here, you can select whether the memory address shown on the left side of the memory window is to be displayed
as a decimal or hexadecimal number.
Display bytes as:
This popup menu makes it possible to choose between different number systems (from binary to hexadecimal) for the
display of the memory content.
Show character string:
Since the content of an 8-bit memory cell can also always be interpreted with the corresponding ASCII code, the
memory content can thus also be interpreted as a sequence of ASCII characters. This usually serves a purpose only
if the examined memory location really contains actual pieces of text (e.g., string variable content). Otherwise,
the displayed font is more reminiscent of old Egyptian hieroglyphs than the content of a computer memory ;-).
Use this checkbox to activate or deactivate the additional display of the memory area in the form of a character
string.
General:
This area offers additional settings for the debugging functions.
Characters per line in variable windows:
Just as for program windows, the number of characters to be max. displayed in one line may be set by users for
Variable Windows as well. The default setting of 255 characters usually suffices.
If you need to track longer strings in the variable window, you might have to increase this value.
Animation delay [in msec]:
The value set here indicates the number of milliseconds the debugger waits between two commands if the program
is executed in animation mode. A value of 1000 thus means that a command is executed every second. The execution
time of the command itself is deducted from the delay time. For example, if a command itself takes 0.3 seconds
to be executed, the debugger waits only another 0.7 seconds until executing the next command.
Permanently update variable windows:
The content of variable windows is usually only updated when the program is in animation mode or is run in single
steps. With this checkbox you specify that the variable windows are always to show the current variable contents
even when the program is in normal mode.
Permanently update memory windows:
This checkbox has the same effect but applies to memory windows.
Step into PROCs and FNs in case of animation:
Procedures and functions are usually treated like BASIC commands when in animation mode. This checkbox can be used
to specify to jump into the procedures and functions and to execute the therein contained individual commands step
by step.
There are three action buttons at the end of the dialog box:
[Execute]
The adjusted settings are executed and are immediately visible or effective. During animation you can therefore
adjust the delay time and activate that time with this button.
[Undo]
The last adjusted setting is canceled.
[Cancel]
The dialog box is closed without accepting the adjusted settings.
Error Messages of the Debugger
The program "Program Name" has unexpectedly quit.
In some cases it can happen that a program to be debugged is terminated spontaneously. In these cases it is
no longer possible to send a message to the debugger. The debugger in turn is not informed of the termination.
If you now still try to apply debugger commands to the terminated program, you will receive this error message.
The addressed memory does not exist.
This error message appears if you try to display a non-existing memory range.
After we have described the debugger components, we would like to illustrate how to use the debugger by using
some examples. The sample programs are equipped with line numbers for easier line reference. The line numbers are
not required to run the program. All variables without postfix are of the long integer type according to the Omikron
Basic editor default setting. If you have modified this setting, you have to consider this when transferring the
program code.
The examples listed here are located in the folder DEMO:Debugger (Demo).
Example 1:
Open a new program window and transfer the following program to an empty window using the 'Copy' and 'Paste' functions. We have added an error to example 1, which we now will find using the debugger.
|
Start the program first with 'Compile & Run'. The program is to calculate the prime numbers between 11 and 120, and it is assumed that the primes < 11 are already known. As you can see, the program runs normal and does not issue any error messages, but it also calculates incorrectly because the number 49 is marked as a prime even though it is divisible by 7.
Quit the program and restart it once more using the menu option 'Debug'. The program stops on line 35 and issues
the error message "integer overflow." Click on [OK]. You are now in the debugger. The position where
the program stopped is marked with a small triangle.
To ascertain the type of error that occurred open a new variable window. Enter I, J,
and Primes(J)into the window and press [Return] after each input so that the variables
appear in different lines. As can be seen, I has the starting value 2, J
the end value 3, and Primes(J)=0, so that the operation
I MOD Primes(J) is not defined and leads to the "Integer overflow."
Just one glance at line 22 shows that an incorrect end value is specified for the control variable J
in the READ loop (2 instead of 3).
Now click on [Terminate] in the Debugger Control. Then add a STOP command to line
18 and correct the wrong end value in line 22 (change 2 to 3).
Then restart the program with 'Debug'. The program is now halted directly behind the STOP
command. Primes(J) is depicted as an error line in the variable window. This is
because this field has not been dimensioned yet. Now advance one step at a time by clicking on [Single Step] in
the Debugger Control. After the DIM command in line 20 has been executed, Primes(J)=0 is displayed correctly in the variable window. If you now proceed with the
READ loop step by step until finished, you can view on the monitor how the prime
numbers are read into the field Primes() one after the other. At the end of the
loop, Primes(J) is again depicted as an error because J
is now 4 and Primes(J) has only been dimensioned up to three.
Once you reach line 25 you can decide whether you want to execute the procedure Display_Numbers
as a command with [Single Step] or if you would like to jump into the procedure with [Step into]. We decided to
use [Step into] to demonstrate the functions of the debugger.
Since PRINT output is directed to the Omikron Basic output window from within the
procedure Display_Numbers, you should move aside the program window so that you
can see the output window.
Of course, now you could execute all commands in the procedure in individual steps but since nothing spectacular
is happening here we would like to take this opportunity to demonstrate another function of the debugger. Click
on [Animation]. The debugger now executes all commands in slow motion. You can now track how the program pointer
progresses through both of the loops and how the numbers are written to the Omikron Basic output window. Once you
have seen enough, click on [Stop]. The program stops at the current location. If you now click on [Step out] all
commands within the procedure are executed and the program is not stopped until line 26, behind the procedure call,
has been reached.
Now keep the [Ctrl] key depressed and clicked on the FOR in line 31 with your
mouse. This sets a breakpoint in front of the FOR depicted as an ellipsis. Click
on [Continue]. The program pointer stops exactly on the breakpoint. If you now click on [Continue] several times,
you can watch how every individual number is examined to see if it is a prime number. The variable window now shows
the variable values of I and the other variables and track in the Omikron Basic
output window how the individual numbers are marked as non-primes.
Now keep the [Ctrl] key depressed and clicked on the breakpoint in line 31. This removes the breakpoint. Set a
new breakpoint in line 43 behind the THEN. Then click on [Continue]. The program
will now always stop when a new line is started.
Remove the breakpoint again and click on [Continue]. All non-primes are marked and the program is in the waiting
loop in line 45.
Click on [Stop]. The program halts in the waiting loop. This works only because the waiting loop contains an EVENT call (COMPILER "EVENT" or Easy_Mesag with EasyGem programming). If your program is in a loop without any EVENT calls, you can still stop the program using [Ctrl] +[C].
Click on [Terminate]. Eratosthenes is terminated, the Debugger Control is hided, and you can edit the source code again to calculate additional prime numbers, for example.
Example 2:
The second example does not contain any errors and serves only to illustrate the debugger functions further. Again, open a new program window and transfer the following program to an empty window using the 'Copy' and 'Paste' functions. Then you have to load the Extension Library with the menu option 'Merge LIBRARY'.
|
Then start the program with 'Debug'. As expected, it stops in line 22, directly behind the STOP
command. Now progress with [Step into] until you reach line 58. Open a new variable window and there enter $Adr. After pressing the [Return] key, the address of the memory block allocated in line
57 is depicted in the variable window as a hex number.
Open a new memory window and then the debugger settings using 'Mode/Preferences/Debugger'. In the now opened dialog,
set 'Bytes per group' to 1, 'Bytes per line' to 8, 'Display bytes as' to decimal and 'Show character string' to
off. Then click on [Execute]. The content of the memory window is now depicted in the form of three-digit decimal
numbers. The character string display disappears. Now transfer the value shown in the variable window for Adr to the address field of the memory window using 'Copy' and 'Paste' and confirm with
[Return].
If you now proceed through the program in individual steps, you can follow in the memory window how the random
numbers are written to memory.
Return to the debugger settings and set the 'Animation delay' to 100. Then confirm with [Execute]. Make sure that
the memory window and the window with the BASIC program remain visible and then click on [Animation] in the Debugger
Control. You can now observe how the random numbers are written to memory every tenth of a second.
Once you have seen enough, click on [Stop] and then on [Step out]. This causes you to leave the procedure, and
then you are located behind the call in line 25.
Set a new breakpoint in line 39 by pressing the [Ctrl] key and click in front of Set_Print_Size with your mouse button to then continue the program. The program stops in line 39. Now click on [Step into]. Although the next item to be executed is a procedure, the program pointer jumps to the next line because the procedure Set_Print_Size is located in a library.
Now bring the Omikron Basic output window to the front. Then click on [Animation]. You can now see how the statistical data are written to the Omikron Basic output window.
Example 3:
This example is a very simple program to easily show which values from MOUSEBUT and INKEY$ are returned if certain
keys are pressed. Again, open a new program window and transfer the program to an empty window using the 'Copy'
and 'Paste' function.
|
Go to the debugger preferences and activate 'Permanently update variable windows'. Then click on [Execute]. Open a new variable window and enter the variables %Mb and %Kbrd$.
Then start the program with 'Debug'. If you now press the mouse button alone or together with any modifier key, you can immediately see in the variable window which bits are set. The same applies to all normal keys of the keyboard. The thus generated ASCII codes, virtual key codes, and modifier key codes are displayed in Kbrd$.
Support | Ordering | Start | Home: http://www.berkhan.de |
© 1997-1999 ![]() |